home *** CD-ROM | disk | FTP | other *** search
/ Java Programmer's Toolkit / Java Programmer's Toolkit.iso / gs3.53 / ps2ascii.ps < prev    next >
Text File  |  1996-01-10  |  21KB  |  640 lines

  1. %    Copyright (C) 1991, 1995 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % Extract the ASCII text from a PostScript file.  Nothing is displayed.
  16. % Instead, ASCII information is written to stdout.  The idea is similar to
  17. % Glenn Reid's `distillery', only a lot more simple-minded, and less robust.
  18.  
  19. % If SIMPLE is defined, just the text is written, with a guess at line
  20. % breaks and word spacing.  If SIMPLE is not defined, lines are written
  21. % to stdout as follows:
  22. %
  23. %    F <height> <width> (<fontname>)
  24. %        Indicate the font height and the width of a space.
  25. %
  26. %    P
  27. %        Indicate the end of the page.
  28. %    S <x> <y> (<string>) <width>
  29. %        Display a string.
  30. %
  31. % <width> and <height> are integer dimensions in units of 1/720".
  32. % <x> and <y> are integer coordinates, in units of 1/720", with the origin
  33. %   at the lower left.
  34. % <string> and <fontname> are strings represented with the standard
  35. %   PostScript escape conventions.
  36.  
  37. % If COMPLEX is defined, the following additional types of lines are
  38. % written to stdout.
  39. %
  40. %    C <r> <g> <b>
  41. %        Indicate the current color.
  42. %
  43. %    I <x> <y> <width> <height>
  44. %        Note the presence of an image.
  45. %
  46. %    R <x> <y> <width> <height>
  47. %        Fill a rectangle.
  48. %
  49. % <r>, <g>, and <b> are RGB values expressed as integers between 0 and 1000.
  50. %
  51. % Note that future versions of this program (in COMPLEX mode) may add
  52. %   other output elements, so programs parsing the output should be
  53. %   prepared to ignore elements that they do not recognize.
  54.  
  55. % Note that this code will only work in all cases if systemdict is writable
  56. % and if `binding' the definitions of operators defined as procedures
  57. % is deferred.  For this reason, it is normally invoked with
  58. %    gs -q -dNODISPLAY -dNOBIND -dWRITESYSTEMDICT ps2ascii.ps
  59.  
  60. % Thanks to J Greely <jgreely@cis.ohio-state.edu> for improvements
  61. % to this code, and to Jerry Whelan <jerryw@abode.ccd.bnl.gov> for
  62. % motivating other improvements.
  63.  
  64. /QUIET true def
  65. systemdict wcheck { systemdict } { userdict } ifelse begin
  66. /.max where { pop } { /.max { 2 copy lt { exch } if pop } bind def } ifelse
  67. /COMPLEX dup where { pop true } { false } ifelse def
  68. /SIMPLE dup where { pop true } { false } ifelse def
  69. /setglobal where
  70.  { pop currentglobal /setglobal load true setglobal }
  71.  { { } }
  72. ifelse
  73.  
  74. % Define a way to store and retrieve integers that survives save/restore.
  75. /.i.string0 (0               ) def
  76. /.i.string .i.string0 length string def
  77. /.iget { cvi } bind def
  78. /.iput { exch //.i.string exch copy cvs pop } bind def
  79. /.inew { //.i.string0 dup length string copy } bind def
  80.  
  81. % We only want to redefine operators if they are defined already.
  82.  
  83. /codef { 1 index where { pop def } { pop pop } ifelse } def
  84.  
  85. % Redefine the end-of-page operators.
  86.  
  87. /erasepage { } codef
  88. /copypage { SIMPLE { (\014) } { (P\n) } ifelse //print } codef
  89. /showpage { copypage erasepage initgraphics } codef
  90.  
  91. % Redefine the fill operators to detect rectangles.
  92.  
  93. /.orderrect    % <llx> <lly> <urx> <ury> .orderrect <llx> <lly> <w> <h>
  94.  {    % Ensure llx <= urx, lly <= ury.
  95.    1 index 4 index lt { 4 2 roll } if
  96.    dup 3 index lt { 3 1 roll exch } if
  97.    exch 3 index sub exch 2 index sub
  98.  } odef
  99. /.fillcomplex
  100.  {    % Do a first pass to see if the path is all rectangles in
  101.     % the output coordinate system.  We don't worry about overlapping
  102.     % rectangles that might be partially not filled.
  103.     % Stack: mark llx0 lly0 urx0 ury0 ... true mark x0 y0 ...
  104.    mark true mark
  105.     % Add a final moveto so we pick up any trailing unclosed subpath.
  106.    0 0 itransform moveto
  107.     { .coord counttomark 2 gt
  108.        { counttomark 4 gt { .fillcheckrect } { 4 2 roll pop pop }  ifelse }
  109.       if
  110.     }
  111.     { .coord }
  112.     { cleartomark not mark exit }
  113.     { counttomark -2 roll 2 copy counttomark 2 roll .fillcheckrect }
  114.    pathforall cleartomark
  115.     { .showcolor counttomark 4 idiv
  116.        { counttomark -4 roll .orderrect
  117.      (R ) //print .show==4
  118.        }
  119.       repeat pop
  120.     }
  121.     { cleartomark
  122.     }
  123.    ifelse
  124.  } odef
  125. /.fillcheckrect
  126.  {    % Check whether the current subpath is a rectangle.
  127.     % If it is, add it to the list of rectangles being accumulated;
  128.     % if not exit the .fillcomplex loop.
  129.     % The subpath has not been closed.
  130.     % Stack: as in .fillcomplex, + newx newy
  131.    counttomark 10 eq { 9 index 9 index 4 2 roll } if
  132.    counttomark 12 ne { cleartomark not mark exit } if
  133.    12 2 roll
  134.     % Check for the two possible forms of rectangles:
  135.     %    x0 y0  x0 y1  x1 y1  x1 y0  x0 y0
  136.     %    x0 y0  x1 y0  x1 y1  x0 y1  x0 y0
  137.    9 index 2 index eq 9 index 2 index eq and
  138.    10 index 9 index eq
  139.     {    % Check for first form.
  140.       7 index 6 index eq and 6 index 5 index eq and 3 index 2 index eq and
  141.     }
  142.     {    % Check for second form.
  143.       9 index 8 index eq and
  144.       8 index 7 index eq and 5 index 4 index eq and 4 index 3 index eq and
  145.     }
  146.    ifelse not { cleartomark not mark exit } if
  147.     % We have a rectangle.
  148.    pop pop pop pop 4 2 roll pop pop 8 4 roll
  149.  } odef
  150. /eofill { COMPLEX { .fillcomplex } if newpath } codef
  151. /fill { COMPLEX { .fillcomplex } if newpath } codef
  152. /rectfill { gsave newpath .rectappend fill grestore } codef
  153. /ueofill { gsave newpath uappend eofill grestore } codef
  154. /ufill { gsave newpath uappend fill grestore } codef
  155.  
  156. % Redefine the stroke operators to detect rectangles.
  157.  
  158. /rectstroke
  159.  { gsave newpath
  160.    dup type dup /arraytype eq exch /packedarraytype eq or
  161.     { dup length 6 eq { exch .rectappend concat } { .rectappend } ifelse }
  162.     { .rectappend }
  163.    ifelse stroke grestore
  164.  } codef
  165. /.strokeline    % <fromx> <fromy> <tox> <toy> .strokeline <tox> <toy>
  166.         % Note: fromx and fromy are in output coordinates;
  167.         % tox and toy are in user coordinates.
  168.  { .coord 2 copy 6 2 roll .orderrect
  169.     % Add in the line width.  Assume square or round caps.
  170.    currentlinewidth 2 div dup .dcoord add abs 1 max 5 1 roll
  171.    4 index add 4 1 roll 4 index add 4 1 roll
  172.    4 index sub 4 1 roll 5 -1 roll sub 4 1 roll
  173.    (R ) //print .show==4
  174.  } odef
  175. /.strokecomplex
  176.  {    % Do a first pass to see if the path is all horizontal and vertical
  177.     % lines in the output coordinate system.
  178.     % Stack: true mark origx origy curx cury
  179.    true mark null null null null
  180.     { .coord 6 2 roll pop pop pop pop 2 copy }
  181.     { .coord 1 index 4 index eq 1 index 4 index eq or
  182.        { 4 2 roll pop pop }
  183.        { cleartomark not mark exit }
  184.       ifelse
  185.     }
  186.     { cleartomark not mark exit }
  187.     { counttomark -2 roll 2 copy counttomark 2 roll
  188.       1 index 4 index eq 1 index 4 index eq or
  189.        { pop pop 2 copy }
  190.        { cleartomark not mark exit }
  191.       ifelse
  192.     }
  193.    pathforall cleartomark
  194.    0 currentlinewidth .dcoord 0 eq exch 0 eq or and
  195.     % Do the second pass to write out the rectangles.
  196.     % Stack: origx origy curx cury
  197.     { .showcolor null null null null
  198.        { 6 2 roll pop pop pop pop 2 copy .coord }
  199.        { .strokeline }
  200.        { }
  201.        { 3 index 3 index .strokeline }
  202.       pathforall pop pop pop pop
  203.     }
  204.    if
  205.  } odef
  206. /stroke { COMPLEX { .strokecomplex } if newpath } codef
  207. /ustroke
  208.  { gsave newpath
  209.    dup length 6 eq { exch uappend concat } { uappend } ifelse
  210.    stroke grestore
  211.  } codef
  212.  
  213. % The image operators must read the input and note the dimensions.
  214. % Eventually we should redefine these to detect 1-bit-high all-black images,
  215. % since this is how dvips does underlining (!).
  216.  
  217. /.noteimagerect        % <width> <height> <matrix> .noteimagerect -
  218.  { COMPLEX
  219.     { gsave setmatrix itransform 0 0 itransform
  220.       grestore .coord 4 2 roll .coord .orderrect
  221.       (I ) //print .show==4
  222.     }
  223.     { pop pop pop
  224.     }
  225.    ifelse
  226.  } odef
  227. /colorimage where
  228.  { pop /colorimage
  229.     { 1 index
  230.        { dup 6 add index 1 index 6 add index 2 index 5 add index }
  231.        { 6 index 6 index 5 index }
  232.       ifelse .noteimagerect gsave nulldevice //colorimage grestore
  233.     } codef
  234.  } if
  235. /.noteimage        % Arguments as for image[mask]
  236.  { dup type /dicttype eq
  237.     { dup /Width get 1 index /Height get 2 index /ImageMatrix get }
  238.     { 4 index 4 index 3 index }
  239.    ifelse .noteimagerect
  240.  } odef
  241. /image { .noteimage gsave nulldevice //image grestore } codef
  242. /imagemask { .noteimage gsave nulldevice //imagemask grestore } codef
  243.  
  244. % Output the current color if necessary.
  245. /.color.r .inew def
  246.   .color.r -1 .iput        % make sure we write the color at the beginning
  247. /.color.g .inew def
  248. /.color.b .inew def
  249. /.showcolor
  250.  { COMPLEX
  251.     { currentrgbcolor
  252.       1000 mul round cvi
  253.       3 1 roll 1000 mul round cvi
  254.       exch 1000 mul round cvi
  255.         % Stack: b g r
  256.       dup //.color.r .iget eq
  257.       2 index //.color.g .iget eq and
  258.       3 index //.color.b .iget eq and
  259.        { pop pop pop
  260.        }
  261.        { (C ) //print
  262.      dup //.color.r exch .iput .show==only
  263.          ( ) //print dup //.color.g exch .iput .show==only
  264.          ( ) //print dup //.color.b exch .iput .show==only
  265.      (\n) //print
  266.        }
  267.       ifelse
  268.     }
  269.    if
  270.  } bind def
  271.  
  272. % Redefine `show'.
  273.  
  274. % Set things up so our output will be in tenths of a point, with origin at
  275. % lower left.  This isolates us from the peculiarities of individual devices.
  276.  
  277. /.show.ident.matrix matrix def
  278. /.show.ident
  279. % { //.show.ident.matrix defaultmatrix
  280. %        % Assume the original transformation is well-behaved.
  281. %   0.1 0 2 index dtransform abs exch abs .max /.show.scale exch def
  282. %   0.1 dup 3 -1 roll scale
  283.  { gsave initmatrix
  284.         % Assume the original transformation is well-behaved.
  285.    0.1 0 dtransform abs exch abs .max /.show.scale exch def
  286.    0.1 dup scale .show.ident.matrix currentmatrix
  287.    grestore
  288.  } bind def
  289. /.coord
  290.  { transform .show.ident itransform
  291.    exch round cvi exch round cvi
  292.  } odef
  293. /.dcoord
  294.  {        % Transforming distances is trickier, because
  295.         % the coordinate system might be rotated.
  296.    .show.ident pop
  297.    exch 0 dtransform
  298.      dup mul exch dup mul add sqrt
  299.      .show.scale div round cvi
  300.    exch 0 exch dtransform
  301.      dup mul exch dup mul add sqrt
  302.      .show.scale div round cvi
  303.  } odef
  304.  
  305. % Remember the current X, Y, and height.
  306. /.show.x .inew def
  307. /.show.y .inew def
  308. /.show.height .inew def
  309. % Remember the last character of the previous string; if it was a
  310. % hyphen preceded by a letter, we didn't output the hyphen.
  311. /.show.last (\000) def
  312. % Remember the current font.
  313. /.font.name 130 string def
  314. /.font.name.length .inew def
  315. /.font.height .inew def
  316. /.font.width .inew def
  317.  
  318. % We have to redirect stdout somehow....
  319. /.show.stdout { (%stdout) (w) file } bind def
  320.  
  321. % Make sure writing will work even if a program uses =string.
  322. /.show.string =string length string def
  323. /.show.=string =string length string def
  324. /.show==only
  325.  { //=string //.show.=string copy pop
  326.    dup type /stringtype eq
  327.     { dup length //.show.string length le
  328.        { dup rcheck { //.show.string copy } if
  329.        } if
  330.     } if
  331.    .show.stdout exch write==only
  332.    //.show.=string //=string copy pop
  333.  } odef
  334. /.show==4
  335.  { 4 -1 roll .show==only ( ) //print
  336.    3 -1 roll .show==only ( ) //print
  337.    exch .show==only ( ) //print
  338.    .show==only (\n) //print
  339.  } odef
  340.  
  341. /.showwidth    % Same as stringwidth, but disable COMPLEX so that
  342.         % we don't try to detect rectangles during BuildChar.
  343.  { COMPLEX
  344.     { /COMPLEX false def stringwidth /COMPLEX true def }
  345.     { stringwidth }
  346.    ifelse
  347.  } odef
  348. /.showfont    % <string> .showfont <string>
  349.  { gsave
  350.     % Try getting the height and width of the font from the FontBBox.
  351.      currentfont /FontBBox .knownget not { {0 0 0 0} } if
  352.      aload pop exch 4 -1 roll sub 3 1 roll exch sub
  353.      2 copy .max 0 ne
  354.       { currentfont /FontMatrix get dtransform
  355.       }
  356.       {    pop pop
  357.     % Fonts produced by dvips, among other applications, have
  358.     % BuildChar procedures that bomb out when given unexpected
  359.     % characters, and there is no way to determine whether a given
  360.     % character will do this.  So for Type 1 fonts, we measure a
  361.     % typical character ('X'); for others, we punt.
  362.     currentfont /FontType get 1 eq
  363.      { (X) .showwidth pop dup 1.3 mul
  364.      }
  365.      {    % No safe way to get the character size.  Punt.
  366.        0 0
  367.      }
  368.     ifelse
  369.       }
  370.      ifelse .dcoord exch
  371.      currentfont /FontName .knownget not { () } if
  372.      dup type /stringtype ne { //.show.string cvs } if
  373.    grestore
  374.     % Stack: height width fontname
  375.    SIMPLE
  376.     { pop pop //.show.height exch .iput }
  377.     { 2 index //.font.height .iget eq
  378.       2 index //.font.width .iget eq and
  379.       1 index //.font.name 0 //.font.name.length .iget getinterval eq and
  380.        { pop pop pop
  381.        }
  382.        { (F ) //print
  383.      3 -1 roll dup //.font.height exch .iput .show==only ( ) //print
  384.          exch dup //.font.width exch .iput .show==only ( ) //print
  385.      dup length //.font.name.length exch .iput
  386.          //.font.name cvs .show==only (\n) //print
  387.        }
  388.       ifelse
  389.     }
  390.    ifelse
  391.  } odef
  392.  
  393. % Define the letters -- characters which, if they occur followed by a hyphen
  394. % at the end of a line, cause the hyphen and line break to be ignored.
  395. /.letter.chars 100 dict def
  396. mark
  397.   65 1 90 { dup 32 add } for
  398. counttomark { StandardEncoding exch get .letter.chars exch dup put } repeat
  399. pop
  400.  
  401. % Define a set of characters which, if they occur at the start of a line,
  402. % are taken as indicating a paragraph break.
  403. /.break.chars 50 dict def
  404. mark
  405.   /bullet /dagger /daggerdbl /periodcentered /section
  406. counttomark { .break.chars exch dup put } repeat
  407. pop
  408.  
  409. % Define character translation to ASCII.
  410. % We have to do this for the entire character set.
  411. /.char.map 500 dict def
  412. /.chars.def { counttomark 2 idiv { .char.map 3 1 roll put } repeat pop } def
  413.     % Encode the printable ASCII characters.
  414. mark 32 1 126
  415.  { 1 string dup 0 4 -1 roll put
  416.    dup 0 get StandardEncoding exch get exch
  417.  }
  418. for .chars.def
  419.     % Encode accents.
  420. mark
  421.   /acute (') /caron (^) /cedilla (,) /circumflex (^)
  422.   /dieresis (") /grave (`) /ring (*) /tilde (~)
  423. .chars.def
  424.     % Encode the ISO accented characters.
  425. mark 192 1 255
  426.  { ISOLatin1Encoding exch get =string cvs
  427.    dup 0 1 getinterval 1 index dup length 1 sub 1 exch getinterval
  428.    .char.map 2 index known .char.map 2 index known and
  429.     { .char.map 3 -1 roll get .char.map 3 -1 roll get concatstrings
  430.       .char.map 3 1 roll put
  431.     }
  432.     { pop pop pop
  433.     }
  434.    ifelse
  435.  }
  436. for .chars.def
  437.     % Encode the remaining standard and ISO alphabetic characters.
  438. mark
  439.   /AE (AE) /Eth (DH) /OE (OE) /Thorn (Th)
  440.   /ae (ae) /eth (dh)
  441.   /ffi (ffi) /ffl (ffl) /fi (fi) /fl (fl)
  442.   /germandbls (ss) /oe (oe) /thorn (th)
  443. .chars.def
  444.     % Encode the other standard and ISO characters.
  445. mark
  446.   /brokenbar (|) /bullet (*) /copyright ((C)) /currency (#)
  447.   /dagger (#) /daggerdbl (##) /degree (o) /divide (/) /dotaccent (.)
  448.   /dotlessi (i)
  449.   /ellipsis (...) /emdash (--) /endash (-) /exclamdown (!)
  450.   /florin (f) /fraction (/)
  451.   /guillemotleft (<<) /guillemotright (>>)
  452.   /guilsingleft (<) /guilsingright (>) /hungarumlaut ("") /logicalnot (~)
  453.   /macron (_) /minus (-) /mu (u) /multiply (*)
  454.   /ogonek (,) /onehalf (1/2) /onequarter (1/4) /onesuperior (1)
  455.   /ordfeminine (-a) /ordmasculine (-o)
  456.   /paragraph (||) /periodcentered (*) /perthousand (o/oo) /plusminus (+-)
  457.   /questiondown (?) /quotedblbase (") /quotedblleft (") /quotedblright (")
  458.   /quotesinglbase (,) /quotesingle (') /registered ((R))
  459.   /section ($) /sterling (#)
  460.   /threequarters (3/4) /threesuperior (3) /trademark ((TM)) /twosuperior (2)
  461.   /yen (Y)
  462. .chars.def
  463.     % Encode a few common Symbol characters.
  464. mark
  465.   /asteriskmath (*) /copyrightsans ((C)) /copyrightserif ((C))
  466.   /greaterequal (>=) /lessequal (<=) /registersans ((R)) /registerserif ((R))
  467.   /trademarksans ((TM)) /trademarkserif ((TM))
  468. .chars.def
  469.  
  470. % Write out a string.  If it ends in a letter and a hyphen,
  471. % don't write the hyphen, and set .show.last to a hyphen;
  472. % otherwise, set .show.last to the character (or \000 if it was a hyphen).
  473. /.show.write    % <string> .show.write -
  474.  { dup length 1 ge
  475.     { dup dup length 1 sub get
  476.       dup 45 eq        % hyphen
  477.        { 1 index length 1 gt
  478.           { 1 index dup length 2 sub get }
  479.       { //.show.last 0 get }
  480.      ifelse
  481.      currentfont /Encoding get exch get
  482.      //.letter.chars exch known
  483.       {    % Remove the hyphen
  484.         exch dup length 1 sub 0 exch getinterval exch
  485.       }
  486.       { pop 0
  487.       }
  488.      ifelse
  489.        }
  490.       if
  491.       //.show.last 0 3 -1 roll put
  492.     }
  493.    if
  494.     { dup currentfont /Encoding get exch get
  495.         % Stack: charcode charname
  496.       dup //.char.map exch .knownget
  497.        { .show.stdout exch writestring pop pop
  498.        }
  499.        { currentfont /Encoding get dup StandardEncoding eq
  500.      exch ISOLatin1Encoding eq or
  501.       {    % Untranslated character in standard encoding
  502.         pop .show.stdout exch write
  503.       }
  504.       {    % Character in non-standard encoding, substitute
  505.         pop pop .show.stdout (*) writestring
  506.       }
  507.      ifelse
  508.        }
  509.       ifelse
  510.     }
  511.    forall
  512.  } odef
  513. /.showstring1
  514.  { currentpoint .coord
  515.    3 -1 roll dup .showwidth 1 index 0 rmoveto
  516.    .dcoord pop
  517.     % Stack: x y string width
  518.    SIMPLE
  519.     { 2 index //.show.y .iget ne
  520.        {    % Try to figure out whether we have a line break
  521.         % or a paragraph break.
  522.      2 index //.show.y .iget sub abs
  523.      //.show.height .iget 1.3 mul ge
  524.      2 index length 0 gt
  525.       { 2 index 0 get currentfont /Encoding get exch get
  526.         //.break.chars exch known { pop true } if
  527.       }
  528.      if
  529.       { (\n\n)    % Paragraph
  530.       }
  531.       { ( )        % Line
  532.       }
  533.      ifelse //print
  534.      //.show.y 3 index .iput
  535.          //.show.x 4 index .iput
  536.        }
  537.        {    % If the word processor split a hyphenated word within
  538.         % the same line, put out the hyphen now.
  539.      //.show.last 0 get 45 eq { (-) //print } if
  540.        }
  541.       ifelse
  542.       3 index //.show.x .iget 10 add gt
  543.        { ( ) //print
  544.        }
  545.       if
  546.       4 1 roll .show.write pop add //.show.x exch .iput
  547.     }
  548.     { (S ) //print .show==4
  549.     }
  550.    ifelse
  551.  } odef
  552. /.showstring
  553.  { dup () eq { pop } { .showstring1 } ifelse
  554.  } bind def
  555.      
  556. % Redefine all the string display operators.
  557.  
  558. /show
  559.  { .showfont .showcolor .showstring
  560.  } codef
  561.  
  562. % We define all the other operators in terms of .show1.
  563. /.show1.string ( ) def
  564. /.show1 { //.show1.string exch 0 exch put //.show1.string .showstring } odef
  565. /ashow
  566.  { .showfont .showcolor
  567.    { .show1 2 copy rmoveto } forall
  568.    pop pop
  569.  } codef
  570. /awidthshow
  571.  { .showfont .showcolor
  572.     { dup .show1 4 index eq { 4 index 4 index rmoveto } if
  573.       2 copy rmoveto
  574.     }
  575.    forall
  576.    pop pop pop pop pop
  577.  } codef
  578. /widthshow
  579.  { .showfont .showcolor
  580.    //.show1.string 0 4 -1 roll put
  581.     { //.show1.string search not { exit } if
  582.       .showstring .showstring
  583.       2 index 2 index rmoveto
  584.     } loop
  585.    .showstring pop pop
  586.  } codef
  587. /kshow
  588.  { .showfont .showcolor
  589.     %**************** Should construct a closure, in case the procedure
  590.     %**************** affects the o-stack.
  591.     { .show1 dup exec } forall pop
  592.  } codef
  593. % We don't really do the right thing with the Level 2 show operators,
  594. % but we do something semi-reasonable.
  595. /xshow { pop show } codef
  596. /yshow { pop show } codef
  597. /xyshow { pop show } codef
  598. /glyphshow
  599.  { currentfont /Encoding .knownget not { {} } if
  600.    0 1 2 index length 1 sub
  601.     {        % Stack: glyph encoding index
  602.       2 copy get 3 index eq { exch pop exch pop null exit } if
  603.     }
  604.    for null eq { (X) dup 0 4 -1 roll put show } { pop } ifelse
  605.  } codef
  606.  
  607. % Redirect the printing operators.
  608.  
  609. /.stdout (_temp_.out) (w) file def
  610. /.stderr (_temp_.err) (w) file def
  611. %****************
  612. %/print { //.stdout exch writestring } codef
  613. %/=only { //.stdout exch write=only } codef
  614. %/==only { //.stdout exch write==only } codef
  615.  
  616. end
  617.  
  618. % Bind the operators we just defined, and all the others if we didn't
  619. % do it before.  Also reenable 'bind' for future files.
  620.  
  621. .bindoperators
  622. NOBIND currentdict systemdict ne and
  623.  { systemdict begin .bindoperators end }
  624. if
  625. NOBIND
  626.  { /bind /.bind load def }
  627. if
  628.  
  629. % Make systemdict read-only if it wasn't already.
  630.  
  631. systemdict wcheck { systemdict readonly pop } if
  632.  
  633. % Restore the current local/global VM mode.
  634.  
  635. exec
  636.